package com.reyco1.media.video
{
	import com.reyco1.display.SmartSprite;
	import com.reyco1.events.YoutubeEvent;
	import com.reyco1.interfaces.IVideoPlayer;
	import com.reyco1.util.Delegate;
	
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLRequest;
	import flash.system.Security;
	import flash.utils.Dictionary;
	
	public class YoutubePlayer extends SmartSprite implements IVideoPlayer
	{
		protected const EXTERNAL_PLAYER_PATH:String = "http://www.youtube.com/apiplayer?version=3";
		protected const THUMBNAIL_PATH:String		= "http://img.youtube.com/vi/{videoID}/3.jpg";
		
		public static var SMALL:String 		= "small";
		public static var MEDIUM:String 	= "medium";
		public static var LARGE:String 		= "large";
		public static var HD720:String 		= "hd720";
		public static var DEFAULT:String 	= "default";
		
		private var loader:Loader;
		private var videoHolder:Sprite;
		private var video:Object;
		private var isReady:Boolean;
		private var playerStates:Dictionary;
		private var onReady:Function;
		private var onReadyParams:Array;
		
		protected var _width:Number;
		protected var _height:Number;
		protected var _volume:Number;
		protected var _state:String;
		protected var _availableQualityLevels:Array;
		
		public function YoutubePlayer(w:Number = 640, h:Number = 480, onReady:Function = null, onReadyParams:Array = null)
		{
			width  = w;
			height = h;
			
			playerStates     = new Dictionary();
			playerStates[-1] = "unstarted";
			playerStates[0]  = "ended";
			playerStates[1]  = "playing";
			playerStates[2]  = "paused";
			playerStates[3]  = "buffering";
			playerStates[5]  = "video cued";
			
			this.onReady = onReady;
			this.onReadyParams = onReadyParams;
		}
		
		override protected function onAdded():void
		{
			Security.allowDomain('www.youtube.com');  
			Security.allowDomain('youtube.com');  
			Security.allowDomain('s.ytimg.com');  
			Security.allowDomain('i.ytimg.com'); 
			
			videoHolder = new Sprite();
			addChild(videoHolder);
			
			isReady = false;
			loadPlayer();
		}
		
		private function loadPlayer():void
		{
			var request:URLRequest = new URLRequest(EXTERNAL_PLAYER_PATH);
			
			loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);
			loader.load(request);
		}
		
		/*
		methods
		*/
		
		public function cueVideo(videoID:String):void
		{
			video.cueVideoById(videoID);
		}
		
		public function loadVideo(videoID:String):void
		{
			video.loadVideoById(videoID);
		}
		
		public function cueVideoByUrl(url:String):void
		{
			video.cueVideoByUrl(url);
		}
		
		public function loadVideoByUrl(url:String):void
		{
			video.loadVideoByUrl(url);
		}
		
		public function play():void
		{
			video.playVideo();
		}
		
		public function pause():void
		{
			video.pauseVideo();
		}
		
		public function stop():void
		{
			video.stopVideo();
		}
		
		public function seek(seconds:Number):void
		{
			video.seekTo(seconds);
		}
		
		public function mute():void
		{
			video.mute();
		}
		
		public function unMute():void
		{
			video.unMute();
		}
		
		public function setSize(w:Number, h:Number):void
		{
			width = w;
			height = h;
			if(isReady == true) video.setSize(width, height);
		}
		
		public function destroy():void
		{
			video.destroy();
			videoHolder.removeChild(loader);
		}
		
		/*
		properties
		*/		
		
		public function get volume():Number
		{
			return _volume;
		}
		
		public function set volume(value:Number):void
		{
			_volume = value;
			video.setVolume(_volume);
		}
		
		public function get muted():Boolean
		{
			return video.isMuted();
		}
		
		override public function get width():Number
		{
			return _width;
		}
		
		override public function set width(value:Number):void
		{
			_width = value;
			if(isReady) video.setSize(_width, video.height);
		}
		
		override public function get height():Number
		{
			return _height;
		}
		
		override public function set height(value:Number):void
		{
			_height = value;
			if(isReady) video.setSize(video.width, _height);
		}
		
		public function get bytesLoaded():Number
		{
			return video.getVideoBytesLoaded();
		}
		
		public function get bytesTotal():Number
		{
			return video.getVideoBytesTotal();
		}
		
		public function get startBytes():Number
		{
			return video.getVideoStartBytes();
		}
		
		public function get state():String
		{
			return _state;
		}
		
		public function get elapsedTime():Number
		{
			return video.getCurrentTime();
		}
		
		public function get availableQualityLevels():Array
		{
			return video.getAvailableQualityLevels();
		}
		
		public function get playbackQuality():String
		{
			return video.getPlaybackQuality();
		}
		
		public function set playbackQuality(quality:String):void
		{
			video.setPlaybackQuality(quality);
		}
		
		public function get duration():Number
		{
			return video.getDuration();
		}
		
		public function get videoUrl():String
		{
			return video.getVideoUrl();
		}
		
		public function get embedCode():String
		{
			return video.getVideoEmbedCode();
		}
		
		override protected function onRemoved():void
		{
			loader.close();	
			
			video.removeEventListener("onReady", handlePlayerReady);
			video.removeEventListener("onError", handlePlayerError);
			video.removeEventListener("onStateChange", handlePlayerStateChange);
			video.removeEventListener("onPlaybackQualityChange", handleQualityChange);			
			video = null;
		}
		
		/*
		handlers
		*/
		
		private function onLoaderInit(e:Event):void
		{
			loader.contentLoaderInfo.removeEventListener(Event.INIT, onLoaderInit);
			
			videoHolder.addChild(loader);
			video = loader.content;
			video.addEventListener("onReady", handlePlayerReady);
			video.addEventListener("onError", handlePlayerError);
			video.addEventListener("onStateChange", handlePlayerStateChange);
			video.addEventListener("onPlaybackQualityChange", handleQualityChange);
			setSize(_width, _height);
		}
		
		private function handlePlayerReady(event:Event):void 
		{
			isReady = true;
			video.setSize(width, height);
			dispatchEvent(new YoutubeEvent(YoutubeEvent.READY));
			
			if(onReady != null) Delegate.execute(onReady, onReadyParams);
		}
		
		private function handlePlayerError(event:Event):void 
		{
			dispatchEvent(new YoutubeEvent(YoutubeEvent.ERROR));
		}
		
		private function handlePlayerStateChange(event:Event):void 
		{
			_state = playerStates[Object(event).data];
			dispatchEvent(new YoutubeEvent(YoutubeEvent.STATE_CHANGE));
		}
		
		private function handleQualityChange(event:Event):void 
		{
			dispatchEvent(new YoutubeEvent(YoutubeEvent.QUALITY_CHANGE));
		}		
	}
}